#pragma once

namespace Melting
{
namespace Parallel
{ 

	//--------------------------------------------------------------------------------------------------------------------
#ifdef WIN32
	typedef DWORD				TLSHandle;
#else // PTHREAD
	typedef pthread_key_t		TLSHandle;
#endif

	//--------------------------------------------------------------------------------------------------------------------
 
	///	Thread Local Storage (TLS in short) provides a way to have data (4bytes wide) specific per thread. 
	template <typename T>
	class TLS
	{
	public:
		/// CTOR - Default value is ZERO
		inline TLS( void );
		/// DTOR
		inline ~TLS( void );		
		
		inline void		Set( T _data );
		inline T		Get( void ); 

	private:
		
		TLSHandle	mHandle;	
	};

#ifdef WIN32
	//----------------------------------------------------------------
	//----------------------------------------------------------------
	template <typename T>
	TLS<T>::TLS( void )
	{
		STATIC_ASSERT( sizeof(T) == sizeof(LPVOID), TLS_works_with_specific_data_size );

		mHandle = TlsAlloc();
		MB_ASSERT( TLS_OUT_OF_INDEXES != mHandle, "No more TLS space. \n" );
	}
	
	//----------------------------------------------------------------
	//----------------------------------------------------------------
	template <typename T>
	TLS<T>::~TLS( void )
	{
		INT32 iSuccess = TlsFree( mHandle );
		MB_ASSERT( 0 != iSuccess, "Could not properly release TLS. \n" );
	}
   
	//----------------------------------------------------------------
	//----------------------------------------------------------------
	template <typename T>
	void TLS<T>::Set( T _data )
	{
		INT32 iSuccess = TlsSetValue( mHandle, (LPVOID)_data );
		MB_ASSERT( 0 != iSuccess, "Could not SetValue on TLS . \n" );
	}
   
	//----------------------------------------------------------------
	//----------------------------------------------------------------
	template <typename T>
	T TLS<T>::Get( void )
	{
		return (T)( TlsGetValue( mHandle ) );
	}

#else
	//----------------------------------------------------------------
	//----------------------------------------------------------------
	template <typename T>
	TLS<T>::TLS( void )
	{
		STATIC_ASSERT( sizeof(T) == sizeof(void*), TLS_works_with_specific_data_size );

		pthread_key_create( & mHandle, nullptr );    
	}
   
	//----------------------------------------------------------------
	//----------------------------------------------------------------
	template <typename T>
	TLS<T>::~TLS( void )
	{
		pthread_key_delete( mHandle );
	}
   
	//----------------------------------------------------------------
	//----------------------------------------------------------------
	template <typename T>
	void TLS<T>::Set( T _data )
	{
		pthread_setspecific( mHandle, (void*)_data );
	}
   
	//----------------------------------------------------------------
	//----------------------------------------------------------------
	template <typename T>
	T TLS<T>::Get( void )
	{
		return (T)( pthread_getspecific( mHandle ) );
	}

#endif
}

}// namespace Melting